namespace Vanilla.UI

import Vanilla
import System

// GADGET
partial class Gadget:
	// BOUNDING RECTANGLE / SIZE
	_rect as Rect
	virtual Rect as Rect:
		get:
			return _rect
		set:
			return if value.IsInvalid
			if HasParent:
				Parent.PauseDrawing()
				Parent.RedrawArea(_rect)
			old = _rect.Round()
			_rect = value.Round()
			//print "${GetType()}.Rect = ${value} (was ${old})"
			Pack() unless _rect.Width == old.Width and _rect.Height == old.Height //cast(int,_rect.Width) == cast(int,old.Width) and cast(int,_rect.Height) == cast(int,old.Height)
			if HasParent:
				Parent.RedrawArea(_rect)
				Parent.ResumeDrawing()
	
	virtual Size as Size:
		get:
			return Size(Rect)
		set:
			Rect = Rect(Rect.X, Rect.Y, value.Width+Rect.X, value.Height+Rect.Y)
	
	Position as Position:
		get:
			return Position(Rect)
		set:
			Rect = Rect(value.X, value.Y, value.X+Rect.Width, value.Y+Rect.Height)
	
	public Expand as bool = true
	
	_MinSize as Size = Size(10,10)
	_MaxSize as Size = Size(10000,10000)
	
	virtual MinSize as Size:
		get:
			return _MinSize
		set:
			return if _MinSize == value
			_MinSize = value
	
	virtual MaxSize as Size:
		get:
			if Expand:
				return _MaxSize
			else:
				return MinSize
		set:
			return if _MaxSize == value
			_MaxSize = value
			
	// PARENT
	public Parent as Box
	
	public HasParent as bool:
		get:
			return Parent != null
	
	// ORDER
	public Order as int:
		get:
			return 0 unless HasParent
			return System.Array.IndexOf(Parent.Children, self)
		set:
			return if Parent == null or Parent.Children == null or value == Order
			
			value = 0 if value < 0
			value = Parent.Children.Length-1 if value >= Parent.Children.Length
			
			//print "ch=${Parent}"
			
			while Order != value:
				my_index = Order
				swp_index as int
				if value > Order:
					swp_index = Order+1 
				else:
					swp_index = Order-1
				
				swp = Parent.Children[swp_index]
				Parent.Children[swp_index] = self
				Parent.Children[my_index] = swp
			
			//print "-> ${Parent}"
	
	virtual def BringToFront ():
		return unless HasParent
		Order = Parent.Children.Length-1
	
	virtual def SendToBack ():
		Order = 0
	
	// EVENT LOOP
	virtual EventLoop as EventLoop:
		get:
			return null if Parent is null
			return Parent.EventLoop
	
	// THEME
	_theme as Theme
	virtual Theme as Theme:
		get:
			return _theme if _theme != null
			return Parent.Theme if HasParent
			return Theme.Default
		set:
			_theme = value
			Pack()
			Redraw()
	
	public ThemedProperties as ThemedProperties
	
	
	
	// CONSTRUCTOR
	def constructor (parent as Box):
		Rect = Rect(0,0,0,0)
		Parent = parent
		if (parent != null):
			parent.Add(self)
	
	// CLONE
	virtual def Clone ():
		return null
	
	// TOSTRING
	def ToString ():
		return "<" + GetType().ToString() + " rect=\"" + Rect.ToString() + "\"/>"
	
	// PACK
	packing_paused as short = 0
	PackingPaused as bool:
		get:
			return packing_paused != 0
	
	needs_pack as bool = false
	
	def PausePacking ():
		packing_paused++
	
	def ResumePacking ():
		packing_paused--
		unless PackingPaused:
			if needs_pack:
				Pack()
				needs_pack = false
	
	public static packing_count = 0
	
	virtual def Pack ():
		if PackingPaused:
			needs_pack = true
			return
		
		packing_count++
		//print "pack ${GetType()} (${packing_count})"
		
		min = MinSize
		max = MaxSize
		
		packing_paused++
		
		PauseDrawing()
		Redraw()
		
		Arrange()
		
		ResumeDrawing()
		
		packing_paused--
		needs_pack = false
		
		//Size = Size(Math.Max(Size.Width,MinSize.Width),Math.Max(Size.Height,MinSize.Height))
		
		unless MinSize == min and MaxSize == max:
			Parent.Pack() unless Parent == null
			Size = Size(Math.Max(MinSize.Width,Size.Width), Math.Max(MinSize.Height,Size.Height))
	
	// Called from inside Pack() to actually arrange
	virtual def Arrange ():
		pass
	
	// CONTAINS
	virtual def Contains (x as double, y as double) as bool:
		return x >= 0 and y >= 0 and x <= Rect.Width and y <= Rect.Height
	
	virtual def Contains (g as Gadget) as bool:
		return false
	
	virtual def ContainsMouseAt (x as double, y as double) as bool:
		return Contains(x,y)
	
	// DESKTOP
	Desktop as Desktop:
		get:
			return Parent if Parent isa Desktop or Parent == null
			return Parent.Desktop
	
	DesktopOffset as Position:
		get:
			return Position(0,0) if Parent == null or self isa Desktop
			return Position if Parent isa Desktop
			p = Parent.DesktopOffset
			return Position(p.X + Position.X, p.Y + Position.Y)
	
	virtual def PopUp (g as Gadget):
		return if Desktop == null
		
		g.Rect = Rect(0,0,0,0)
		Desktop.Add(g)
		o = DesktopOffset
		if o.Y + Size.Height + g.MinSize.Height <= Desktop.Size.Height:
			g.Rect = Rect(Position(o.X, o.Y+Size.Height), Size(Math.Max(Size.Width, g.MinSize.Width), g.MinSize.Height))
		else:
			g.Rect = Rect(Position(o.X, o.Y-g.MinSize.Height), Size(Math.Max(Size.Width, g.MinSize.Width), g.MinSize.Height))
	
	virtual def KeyDown (c as char, k as Key):
		pass
		//print "key down ${c} ${k}"
	
	virtual def KeyUp (c as char, k as Key):
		//print "key up ${c} ${k}"
		KeyPress(c,k)
	
	virtual def KeyPress (c as char, k as Key):
		pass
	
	virtual def Reparented (old as Box, new as Box):
		pass

